镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Check a type once per write, so a nested expression body runs twice, not depth + 3 times [patch] - #205

Open
matt-edmondson wants to merge 2 commits into
mainfrom
fix/expression-body-renders-202
Open

matt-edmondson wants to merge 2 commits into
mainfrom
fix/expression-body-renders-202

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #202

What was wrong

A property's ExpressionBodyFactory is rendered once to check it and once to write it. The check itself repeated at every level:

  • ClassTemplate.WriteTo validated its whole subtree, and then each nested type's WriteTo validated its own subtree again.
  • AddSourceFile validated every type, then AddClasses validated them again.

At depth 3 the callback ran 6 times. A stateful factory, such as a counter for unique names, wrote different code depending on how deeply its class was nested.

Change

A template write now opens a scope on the CodeBlocker (BeginTemplateWrite, internal). The scope records which ClassTemplates have been checked, by reference. ClassTemplate.WriteTo, ClassTemplate.Validate (for nested types), AddClasses and AddSourceFile skip a type that was already checked in the scope. The set is cleared when the outermost write ends, whether or not it succeeded.

  • The documented "check, then write" pass stays: the callback runs exactly 2 times, however deeply its type is nested.
  • Types are matched by reference, with a small comparer, because ReferenceEqualityComparer doesn't exist on netstandard2.0/2.1. A different type that a BodyFactory writes into the same CodeBlocker is still checked.

Tests

  • New: ANestedPropertysExpressionBodyRunsOnceToCheckAndOnceToWrite. Depth 3 through AddSourceFile, ClassTemplate.WriteTo and AddClasses. Each expects 2 calls. Before the fix: 6.
  • New: AStatefulExpressionBodyWritesTheSameCodeWhereverItsClassIsNested. This is the issue's repro: standalone and nested-in-a-file now both write First => 2 / Second => 3. Before, the nested case wrote 8 / 9.
  • New guard: AClassWrittenFromInsideABodyFactoryIsStillChecked. An invalid type written from a method body callback still throws. It passes before and after, and keeps the skip from widening.
  • With the fix reverted, the first two fail. Full suite on Linux / .NET 10: 380/380 passed.

This doesn't touch #176 (throwing BodyFactories leave half-written members). That needs the larger pre-render restructure.


Generated by Claude Code

…not depth + 3 times [patch]

ClassTemplate.WriteTo validated its whole subtree, and every nested type's WriteTo
validated its own subtree again; AddSourceFile and AddClasses each validated all
types once more. A property's ExpressionBodyFactory ran depth + 3 times, so a
stateful factory wrote different code depending on how deeply its class sat.

A template write now opens a scope on the CodeBlocker that records which types
have been checked, by reference. A type already checked in the scope is not
checked again, so the callback runs once to check and once to write. A different
type that a callback writes is still checked.

Fixes #202

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017vfJW5YjyP4TWYsDuKLv95
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants